/*
    SqliteHelper
    1. 创建/打开对应的数据库文件
    2. 针对打开的数据库文件进行操作
        [1] 表操作
        [2] 数据操作
    3. 关闭数据库文件
*/

#include <iostream>
#include <sqlite3.h>
#include <vector>
#include <string>

class SqliteHelper
{
public:
    typedef int(*SqliteCallback)(void*,int,char**,char**); // 回调函数，用于决定如何处理得到数据的函数

    SqliteHelper(const std::string &dbfile)
        : _dbfile(dbfile),
          _handler(nullptr)
    {
    }

    bool open(int safe_level = SQLITE_OPEN_FULLMUTEX)
    {
        /*
        flag:
            SQLITE_OPEN_READWRITE -- 以可读可写方式打开数据库文件
            SQLITE_OPEN_CREATE -- 不存在数据库文件则创建
            SQLITE_OPEN_NOMUTEX--多线程模式，只要不同的线程使用不同的连接即可保证线程安全
            SQLITE_OPEN_FULLMUTEX--串行化模式
        返回： SQLITE_OK 表示成功
        */
        // int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
        int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);
        if(ret != SQLITE_OK)
        {
            std::cout << "打开/创建sqlite数据库失败" << std::endl;
            std::cout << sqlite3_errmsg(_handler);
            return false;
        }
        return true;
    }

    bool exec(const std::string &sql, SqliteCallback cb, void* arg)
    {
        /*
        int sqlite3_exec(sqlite3*, char *sql, int(*callback)(void*,int,char**,char**), void* arg, char **err)
            int (*callback)(void*,int,char**,char**)
            void* : 是设置的在回调时传入的 arg 参数
            int：一行中数据的列数
            char**：存储一行数据的字符指针数组
            char**：每一列的字段名称
            这个回调函数有个 int 返回值，成功处理的情况下必须返回 0，返回非 0
            会触发 ABORT 退出程序
            返回： SQLITE_OK 表示成功
        */
       int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
       if(ret != SQLITE_OK)
       {
            std::cout << sql << std::endl;
            std::cout << "执行语句失败: ";
            std::cout << sqlite3_errmsg(_handler) << std::endl;
            return false;
       }
       return true;
    }

    bool close()
    {
        /*
            int sqlite3_close_v2(sqlite3*); 推荐使用--无论如何都会返回SQLITE_OK
        */
        if(_handler) 
        {
            sqlite3_close_v2(_handler);
            return true;
        }
        return false;
    }

private:
    std::string _dbfile; /* 数据库文件路径 */
    sqlite3 *_handler;   /* 操作句柄 */
};